package com.aiwiown.snackmq.common.protocol;

import com.aiwiown.snackmq.common.auth.Permission;
import com.aiwiown.snackmq.common.auth.User;
import com.aiwiown.snackmq.common.cluster.BrokerId;
import com.aiwiown.snackmq.common.routing.ExchangeType;
import com.aiwiown.snackmq.common.serialization.JsonSerializer;
import com.aiwiown.snackmq.common.serialization.SerializerFactory;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.io.Serializable;
import java.util.List;
import java.util.Map;

/**
 * 表示用于修改集群元数据的命令。
 * 该类现在是一个更直接的数据传输对象 (DTO)。
 */
@Getter
@NoArgsConstructor
public class MetadataOperation implements Serializable {

    private static final long serialVersionUID = -8555685079531439185L;
    /**
     * 操作类型，定义了元数据操作的具体行为。
     */
    private OperationType type = OperationType.METADATA;
    /**
     * 具体元数据操作类型
     */
    private MetadataOperationType operationType;

    // --- 核心修复 1: 将存储字符串的 Map 替换为直接持有数据对象 ---
    // 这避免了"二次序列化"的问题。

    /**
     * 主题名称，用于创建主题或更新分区分配。
     */
    private String topicName;

    /**
     * 分区数量，表示主题的分区总数。
     */
    private int partitions;

    /**
     * 副本因子，表示每个分区的副本数量。
     */
    private int replicationFactor;

    /**
     * 交换机名称，用于声明交换机。
     */
    private String exchangeName;

    /**
     * 交换机类型，定义了交换机的行为（如 DIRECT、TOPIC 等）。
     */
    private ExchangeType exchangeType;

    /**
     * 队列名称，用于绑定队列到交换机。
     */
    private String queueName;

    /**
     * 路由键，用于绑定队列到交换机。
     */
    private String routingKey;


    // --- 【新增】RBAC 相关字段 ---
    /**
     * 用户
     */
    private User user;
    /**
     * 角色名称
     */
    private String roleName;
    /**
     * 权限列表
     */
    private List<Permission> permissions;

    // --- 【新增】删除操作所需字段 ---
    private String usernameToDelete;
    private String roleNameToDelete;

    /**
     * 分区分配映射，表示每个分区及其对应的 Broker 列表。
     */
    private Map<TopicPartition, List<BrokerId>> partitionAssignment;

    /**
     * 需要更新 Leader 的分区。
     */
    private TopicPartition topicPartitionForLeaderUpdate;

    /**
     * 新的 Leader 节点标识。
     */
    private BrokerId newLeader;

    private static final JsonSerializer SERIALIZER = SerializerFactory.getJsonSerializer();

    // --- 工厂方法被重构，以直接设置字段 ---

    /**
     * 创建一个新的创建主题操作。
     *
     * @param topicName         主题名称。
     * @param partitions        分区数量。
     * @param replicationFactor 副本因子。
     * @return 返回一个封装了创建主题操作的 MetadataOperation 实例。
     */
    public static MetadataOperation newCreateTopicOperation(String topicName, int partitions, int replicationFactor) {
        MetadataOperation op = new MetadataOperation();
        op.type = OperationType.METADATA;
        op.operationType = MetadataOperationType.CREATE_TOPIC;
        op.topicName = topicName;
        op.partitions = partitions;
        op.replicationFactor = replicationFactor;
        return op;
    }


    /**
     * 创建一个新的删除主题操作。
     *
     * @param topicName 主题名称。
     * @return 删除主题操作的 MetadataOperation 实例。
     */
    public static MetadataOperation newDeleteTopicOperation(String topicName) {
        MetadataOperation op = new MetadataOperation();
        op.type = OperationType.METADATA;
        op.operationType = MetadataOperationType.DELETE_TOPIC;
        op.topicName = topicName;
        return op;
    }

    /**
     * 创建一个新的声明交换机操作。
     *
     * @param exchangeName 交换机名称。
     * @param type         交换机类型。
     * @return 返回一个封装了声明交换机操作的 MetadataOperation 实例。
     */
    public static MetadataOperation newDeclareExchangeOperation(String exchangeName, ExchangeType type) {
        MetadataOperation op = new MetadataOperation();
        op.type = OperationType.METADATA;
        op.operationType = MetadataOperationType.DECLARE_EXCHANGE;
        op.exchangeName = exchangeName;
        op.exchangeType = type;
        return op;
    }

    /**
     * 创建一个新的删除交换机操作。
     *
     * @param exchangeName 交换机名称。
     * @return 删除交换机操作的 MetadataOperation 实例。
     */
    public static MetadataOperation newDeleteExchangeOperation(String exchangeName) {
        MetadataOperation op = new MetadataOperation();
        op.type = OperationType.METADATA;
        op.operationType = MetadataOperationType.DELETE_EXCHANGE;
        op.exchangeName = exchangeName;
        return op;
    }

    /**
     * 创建一个新的绑定队列操作。
     *
     * @param queueName    队列名称。
     * @param exchangeName 交换机名称。
     * @param routingKey   路由键。
     * @return 返回一个封装了绑定队列操作的 MetadataOperation 实例。
     */
    public static MetadataOperation newBindQueueOperation(String queueName, String exchangeName, String routingKey) {
        MetadataOperation op = new MetadataOperation();
        op.type = OperationType.METADATA;
        op.operationType = MetadataOperationType.BIND_QUEUE;
        op.queueName = queueName;
        op.exchangeName = exchangeName;
        op.routingKey = routingKey;
        return op;
    }

    /**
     * 创建一个新的解绑队列操作。
     *
     * @param queueName    队列名称。
     * @param exchangeName 交换机名称。
     * @param routingKey   路由键。
     */
    public static MetadataOperation newUnbindQueueOperation(String queueName, String exchangeName, String routingKey) {
        MetadataOperation op = new MetadataOperation();
        op.type = OperationType.METADATA;
        op.operationType = MetadataOperationType.UNBIND_QUEUE;
        op.queueName = queueName;
        op.exchangeName = exchangeName;
        op.routingKey = routingKey;
        return op;
    }

    /**
     * 创建一个新的更新分区分配操作。
     *
     * @param newAssignment 新的分区分配映射。
     * @return 返回一个封装了更新分区分配操作的 MetadataOperation 实例。
     */
    public static MetadataOperation newUpdatePartitionAssignmentOperation(Map<TopicPartition, List<BrokerId>> newAssignment) {
        MetadataOperation op = new MetadataOperation();
        op.type = OperationType.METADATA;
        op.operationType = MetadataOperationType.UPDATE_PARTITION_ASSIGNMENT;
        op.partitionAssignment = newAssignment;
        return op;
    }

    /**
     * 创建一个新的更新 Leader 操作。
     *
     * @param partition 需要更新 Leader 的分区。
     * @param newLeader 新的 Leader 节点标识。
     * @return 返回一个封装了更新 Leader 操作的 MetadataOperation 实例。
     */
    public static MetadataOperation newUpdateLeaderOperation(TopicPartition partition, BrokerId newLeader) {
        MetadataOperation op = new MetadataOperation();
        op.type = OperationType.METADATA;
        op.operationType = MetadataOperationType.UPDATE_LEADER;
        op.topicPartitionForLeaderUpdate = partition;
        op.newLeader = newLeader;
        return op;
    }

    /**
     * 【新增】创建 "创建用户" 操作的工厂方法。
     *
     * @param user 要创建的用户对象
     * @return 返回一个封装了创建用户操作的 MetadataOperation 实例
     */
    public static MetadataOperation newCreateUserOperation(User user) {
        MetadataOperation op = new MetadataOperation();
        op.type = OperationType.METADATA;
        op.operationType = MetadataOperationType.CREATE_USER;
        op.user = user;
        return op;
    }

    /**
     * 【新增】创建 "设置角色权限" 操作的工厂方法。
     *
     * @param roleName    角色名称
     * @param permissions 该角色的权限列表
     * @return 返回一个封装了设置角色权限操作的 MetadataOperation 实例
     */
    public static MetadataOperation newSetRolePermissionsOperation(String roleName, List<Permission> permissions) {
        MetadataOperation op = new MetadataOperation();
        op.type = OperationType.METADATA;
        op.operationType = MetadataOperationType.SET_ROLE_PERMISSIONS;
        op.roleName = roleName;
        op.permissions = permissions;
        return op;
    }

    /**
     * 【新增】创建 "删除用户" 操作的工厂方法。
     */
    public static MetadataOperation newDeleteUserOperation(String username) {
        MetadataOperation op = new MetadataOperation();
        op.type = OperationType.METADATA;
        op.operationType = MetadataOperationType.DELETE_USER;
        op.usernameToDelete = username;
        return op;
    }

    /**
     * 【新增】创建 "删除角色" 操作的工厂方法。
     */
    public static MetadataOperation newDeleteRoleOperation(String roleName) {
        MetadataOperation op = new MetadataOperation();
        op.type = OperationType.METADATA;
        op.operationType = MetadataOperationType.DELETE_ROLE;
        op.roleNameToDelete = roleName;
        return op;
    }

    /**
     * 将当前对象序列化为字节数组。
     *
     * @return 返回序列化后的字节数组。
     */
    public byte[] toBytes() {
        return SERIALIZER.serialize(this);
    }

    /**
     * 从字节数组反序列化为 MetadataOperation 对象。
     *
     * @param data 字节数组数据。
     * @return 返回反序列化后的 MetadataOperation 对象；如果数据为空，则返回 null。
     */
    public static MetadataOperation fromBytes(byte[] data) {
        if (data == null || data.length == 0) return null;
        return SERIALIZER.deserialize(data, MetadataOperation.class);
    }

    public MetadataOperationType getOperationType() {
        return operationType;
    }
}